1. Características y ventajas
-
TS (TypeScript) funciona en tiempo de compilación. Lo que ejecutamos en el navegador es JS (JavaScript).
-
Nos aporta seguridad a través del tipado de datos.
-
A día de hoy muchos frameworks, aplicaciones web y apps de escritorio funcionan, o están desarrolladas con TS.
-
VSCODE ya trae instalado TypeScript (está de hecho desarrollado en TypeScript), y si tenemos instalada la extensión Error Lens, podremos enseguida ver la notificación de los errores en nuestro código.
-
TS utiliza la inferencia en su código. Podemos definir la inferencia de código en TS, como la capacidad de detectar el tipado de datos, o no en un contexto específico, ya sea habiendo realizado nosotros el tipado, o porque ciertos contextos tienen esta capacidad de manera implícita. Inferir, significa observar los objetos que hayamos definido en nuestro código, y saber de antemano qué propiedades y tiene, y de qué tipos son. Si intentamos acceder a una propiedad que no exista, nos avisará (para ver esto en vivo es conveniente, una vez más, tener Error Lens instalado en VSCODE).
2. Tipado
El tipado de datos lo hacemos de manera explícita:
El tipado también podría realizarse de manera implícita. Esto ocurre, simplemente al asignar un valor de un tipo.
A partir de aquí a la variable usuario1 no podría asignársele ningún dato que no sea un string.
Tipos de dato: String
Tipos de dato: Number
Tipos de dato: Boolean
Tipos de dato: Arrays
Tipos de dato: Tuplas
Tipos de dato: Any
Cuando TS no sabe inferir un tipo de dato, automáticamente le asigna un tipo de dato any. Este tipo de dato, más allá de poder significar "cualquier tipo de dato", signigica "Ignórame el tipado de TypeScript".
Se recomienda evitarlo.
Tipos de dato: Unknown
Es un tipo de dato que especifica que "todavía no sabemos qué tipo de dato es". De esta forma, que en cuanto intentemos acceder a ciertas propiedades de la variable, TS nos irá adviertiendo de que andemos con cuidado intentando a acceder a una proopiedad length, por ejemplo, que pertenece al objeto string nativo.
Hay más tipos de datos que iremos explicando. Este enlace muestra todos los tipos de datos: Documentación oficial: tipos de datos
3. Inferencia de datos
Inferir, significa observar los objetos que hayamos definido en nuestro código, y saber de antemano qué propiedades y tiene, y de qué tipos son. Si intentamos acceder a una propiedad que no exista, nos avisará (para ver esto en vivo es conveniente, una vez más, tener Error Lens instalado en VSCODE).
No pensemos que el tipado de datos sirve solamente como feedback que nos da nuestro editor de código con TS. La inferencia de datos, como iremos viendo, permite que ciertas funcionalidades de TS puedan hacer lo que hacen. Veamos algunos ejemplos básicos:
Ejemplo Number:
Dados:
...si a es un número
... y b también
TS sabe que c es un número, al ser la suma de a + b:
Ejemplo String:
No podemos asignar un tipo que no sea el que hayamos tipado previamente (ya sea al definiéndolo como string literlamente con la palabra "strings", o simplemente dándole un string como valor), ni tampoco podemos acceder a una propiedad que no pertenezca al tipo de dato string.
4. Funciones
Tipar parámetros en una función
Debemos tipar los parámetros, de tal manera que no le podamos pasar cualquier tipo de dato. Tengamos en cuenta lo mencionado con anteriorirad, el tipo de dato que le pasemos, nos permitirá acceder a los métodos que pertenezcan al objeto nativo de ese tipo de dato (ejemplo: tipo string --> length)
Parámetro de tipo objeto
Si le pasamos un objeto como parámetro, tampoco podemos pasrle un objeto, con propiedades que tengan cualquier tipo de valor. Además en este caso no sería correcto tiparlas al pasarlas como parámetro, ya que entra en conflicto con la sintaxis de JavaScript:
Incorrecto
Para poder tipar las propiedades de un objeto pasado como parámetro, podemos hacerlo de dos formas. En la segunda forma, tenemos que tener en cuenta que dentro de la función, tendremos que extraer los valores en una constante.
Correcto
Correcto
Return
También debemos tener en cuenta algunos escenarios cuando utilicemos return en TS, ya que para este caso si que disponemos de inferencia.
Dado lo siguiente:
Si nos ponemos encima con el ratón, TS nos dirá que esta función retorna un number, ya que en el objeto pasado como parámetro, se ha determinado así para el valor retornado.
Si tipamos una nueva variable como string, e intentamos darle como valor lo que retorne la función, obtendremos un error, ya que los tipos no se corresponden.
Si le cambiamos el valor retornado a string, el return age se nos quejará
Funciones como parámetros
En este sencillo callback, generamos una función que definirá un valor string, y se pasará la ejecución de dicha función a la segunda como parámetro.
En este punto, esto está sin tipar, y por defecto todos los valores están como "any"
El name, es fácil de solventar:
Pero en el segundo, podríamos incurrir en un error muy común, que es tipar las funciones como "Function". Aunque funcionar, funcionaría, no es correcto.
Utilizar el tipado "Function", en la práctica, es algo demasiado general. Es casi como utilizar "any", en funciones. Veamos cómo se haría correctamente:
1 - Sacamos el callback a una constante y le quitamos el tipado "Function". Esto nos dirá que fn es de tipo any
2 - Un tipado más explícito de la función se realiza tipando el parámetro que le pasamos, así como el valor retornado. En las imágenes, vemos dos ejemplos, void y string.

En el caso del string, como podemos observar, obtenemos un error, ya que el parámetro que estamos pasando abajo es una función. Pero, ¿qué significa void?
Especificamos un retorno de void cuando la función no devuelve nada. Esto, realmente, es algo bastante habitual, ya que en muchos funciones no necesitamos retornar nada. En TS, en estos casos, utilizamos void.
Incluso, dado el caso de que nuestra función retornara algo, habiendo especificado void, ya no estaríamos atados a un tipo de dato específico como string o number (esto puede causar algo de confusión con el tipo de dato any, pero simplemente, para que sepamos que también funciona).
Tipar arrow funcitons
Estas serían dos sintaxis válidas para tipar funciones flecha.
Tipo never en funciones
El tipo never se utiliza para funciones que sepamos que nunca van a devolver nada. Esta función lanza un error personalizado a través del string pasado como parámetro, de tal manera que no devuelve ni un string, ni un número ni una función...etc.
Tipos never, void y any en funciones
Por hacer un repaso entre los tres tipos de datos "vacíos" o "ambiguos":
Never: Nunca devuelve nada. Se utiliza en pocos casos.
Void: Por defecto va a devolver vacío. Si el parámetro que hay que pasarle, es de tipo función, y la función que pasamos devuelve algo, void aceptará que la función devuelva ese algo.
Any: Valor que se asigna por defecto al no tipar nada, o que podemos especificar si queremos que el valor sea "cualquiera". Este caso no es recomendable.
Inferencia en funciones anónimas según el contexto
En la mayoría de casos no existe en inferencia de datos en las funciones, pero en el caso de las funciones anónimas, sí que hay.
En este ejemplo, tenemos una función anónima para iterear sobre el array avengers. Si intentamos utilizar un método para cada string...
...veremos que en este caso, TS no se nos queja, ya que en este caso, si que tiene la capacidad de infferir los tipos de datos. Podemos decir que esto se debe a que el método foreach ya está analizando los tipos de datos. Esto mismo pasa para todos los tipos de métodos con arrays como map, for, forof...etc.
5. Objetos
Los objetos tienen inferencia de datos.


Tanto si intentamos acceder asignar un valor que no corresponda con el tipado de la propiedad en cuestión (primera imagen), como si intentamos crear una propiedad nueva (segunda imagen), la inferencia de datos implícita en los objetos se nos quejará.
Podemos entender estos requisitos, como un "contrato" que hacemos con TS cuando queremos crear un objeto.
6. Types
Hilando con el tema de los objetos, veamos el siguiente caso:
En este caso, aunque estamos creando thor que tiene las mismas propiedades que hero, no podemos determinar al 100% que son del mismo tipo. Aquí entran en juego los types, o type alias que nos permite definir cómo es el objeto Hero.
Nota: Importante, por convención, cuando creamos un tipo custom con Type Alias, siempre se hace en PascalCase:
De esta manera, podemos definir nuestro tipo Hero, tipando el objeto, y la función para crear un nuevo elemento de tipo Hero.
Podemos ir un poco más allá, podemos incluso pasar un parámetro de tipo Hero, ya que ya lo hemos definido como un tipo. Tengamos en cuenta, eso sí, que tendremos que extarer las propiedades al pasar el Hero como parámetro.
Types: Optional properties
Vamos a seguir utilizando como base el ejemplo anterior. Si queremos añadir una propiedad nueva en la función para crear el hero, TS se nos va a quejar.
Para que la propiedad isActive funcione, tenemos que definirla como optional property.
Como podemos ver, tanto si le queremos añadir la propiedad en la función, como si lo hacemos en el objeto, TS se nos queja por un lado o por otro. Para no estar atado a ciertas propiedades, las debemos definir como opcionales.
La sintaxis utilizada es la interrogación que vemos para la propiedad isActive.
Types: Optional changin operator
Vamos a añadirle un id, también lo haremos con la optional property.
Vamos ahora a añadirle el id. Vamos a definir la propiedad id también como optional property con la interrogación, diciéndole que puede ser number o undefined (si no la hemos definido). Al definir la propiedad, vamos a convertirla a string con el método toString() que convierte un número en cadena.
Como podemos observar, TS nos marcará el id con la interrogación. Esta sintaxis abreviada se llama optional changing operator, y basicamente está preguntando si la optional property existe. Si es que sí, nos permite manipularla, digamos que nos da un extra de seguridad/buenas prácticas.
Types: Atributo Read only
Podemos tener un mayor control sobre las propiedades de un type, de tal manera que no le podamos asignar cualquier cosa a aun valor, por ejemplo, al ID. Si nosotros autogeneramos el id de manera dinámica en un punto de nuestro código, podemos impedir que pase esto:
...haciendo lo esto:
De esta manera, TS se nos quejará si intentamos ponerle cualquier cosa al id. No estamos evitando que esto pase, pero estamos haciendo que el código muestre la alerta en caso de que esto pase.
Types: Template union types
Dentro del type Hero, de cara a que no nos tengamos que preocupar de la generación del id, vamos a generarlo de manera dinámica dentro de la definición del type.
Para ello vamos a utilizar crypto.randomUUID(), que nos sacará un id con un formato aleatorio y de muchos caracteres.
Gracias al templante union type, podremos generar un tipo que se asegure de que el id generado tiene este formato.
Si le intento pasar otra cosa, se me quejará
Types: Union types
Los union types nos permite añadir el caracter "or" | (en este caso es solo un caracter, no como en JS), para especificar que un tipo puede aceptar varios tipos de valor.
Si le pasamos uno diferente, se quejará.
Podríamos llegar a ser así de explícitos:
Types: Intersection types
Los intersection types nos permiten utilizar el caracter "and" & (en este caso es solo un caracter, no como en JS) lo cual nos permitiría dividir los tipos de esta manera:
Types: Type index
Podemos extraer propiedades concretas de un type para guardarlas en una nueva constante.
Types: Type from value
También podemos crear types desde unos valores dados desde una variable, constante u objeto.
Types: Type from function return
Con esta sintaxis < > y con la palabra ReturnType podemos extraer los tipos de los valores retornados por una función, y así, generar un nuevo type.
Por detrás, todo esto es gracias a la inferencia de datos.
7. Arrays
Evidentemente, los arrays no escapan al tipado en TS.
Como detalle interesante para entender mejor lo que está pasando, veamos que al añadir los corchetes vacíos, estamos tipando de manera implícita un tipo never. Por ello, la inferencia de datos de TS hace que VSCODE nos devuelva un error.
Si queremos un array de strings, lo especificamos de esta manera, pero no le podremos pasar ningún otro tipo de dato.
La siguiente sintaxis también es válida, por si la vemos por ahí, para que no nos asuste.
Un error muy común que suele cometer la gente es este.
Le estamos diciendo que es un array, pero todo de números o todo de strings. Si que remso tener un array de tipos de dato combinado, esta sería la sintaxis correcta.
8. Matrices y tuplas
Las matrices, o arrays de arrays, las definimos de la siguiente manera:
Veamos con un ejemplo práctico las matrices, las tuplas y algunos conceptos que ya hemos visto. Como podemos ver en la imagen, esto sería un tres en raya. Para poder limitar los caracteres que queremos meter, utilizamos el tipado.
Ahora ya, solo podemos meter los caracteres correspondientes al juego. No obstante, nos faltaría limitar el número de elementos a introducir en el array, para ello vamos a crear una tupla.
Como vemos, si ahora intentamos meter más de tres elementos, la inferencia de código se nos queja. Tenemos que meter el mismo número que delimita la definición de la tupla.
Como curiosidad, decir que el método useState de React, es una tupla delimitada por un un string y una función. Obviamente, aquí nos está devolviendo un error.
Otro ejemplo de tupla, sería el RGB. Un array delimitado a tres elementos, y que solo puede recibir valores numéricos entre el 0 y el 255.